package com.wujunshen.thread.producerandconsumer.notify;

import org.apache.commons.lang3.exception.ExceptionUtils;

import java.util.LinkedList;
import java.util.Queue;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * @author frank woo(吴峻申) <br>
 *     email:<a href="mailto:frank_wjs@hotmail.com">frank_wjs@hotmail.com</a> <br>
 * @date 2020/7/16 03:22<br>
 */
@Data
@Slf4j
public class Storage {
  /** 仓库最大存储量 */
  private static final int MAX_SIZE = 100;

  /** 仓库存储的载体 */
  private final Queue<Object> list = new LinkedList<>();

  /**
   * 生产num个产品
   *
   * @param num 生产数量
   */
  public void produce(int num) {
    // 同步代码段
    synchronized (list) {
      // 如果仓库剩余容量不足
      while (list.size() + num > MAX_SIZE) {
        log.info("【要生产的产品数量】: {}", num);
        log.info("【库存量】: {} 暂时不能执行生产任务!", list.size());

        try {
          list.wait(); // 由于条件不满足，生产阻塞
        } catch (InterruptedException e) {
          log.error(ExceptionUtils.getStackTrace(e));
        }
      }

      // 生产条件满足情况下，生产num个产品
      for (int i = 1; i <= num; ++i) {
        list.add(new Object());
      }

      log.info("【已经生产产品数】: {}", num);
      log.info("【现仓储量为】: {}", list.size());

      list.notifyAll();
    }
  }

  /**
   * 消费num个产品
   *
   * @param num 消费数量
   */
  public void consume(int num) {
    // 同步代码段
    synchronized (list) {
      // 如果仓库存储量不足
      while (list.size() < num) {
        log.info("【要消费的产品数量】: {}", num);
        log.info("【库存量】: {} 暂时不能执行生产任务!", list.size());

        try {
          // 由于条件不满足，消费阻塞
          list.wait();
        } catch (InterruptedException e) {
          log.error(ExceptionUtils.getStackTrace(e));
        }
      }

      // 消费条件满足情况下，消费num个产品
      for (int i = 1; i <= num; ++i) {
        list.remove();
      }

      log.info("【已经消费产品数】: {}", num);
      log.info("【现仓储)量为】: {}", list.size());

      list.notifyAll();
    }
  }
}
